package com.upb.webserver.chain;

import com.upb.webserver.chainorg.ChainOrgManager;
import com.upb.webserver.common.constant.Constant;
import com.upb.webserver.common.enums.ChainOrAppStatusEnum;
import com.upb.webserver.common.enums.ChainTypeEnum;
import com.upb.webserver.common.enums.PlatformEnum;
import com.upb.webserver.common.enums.TableNameEnum;
import com.upb.webserver.common.exception.WebServerException;
import com.upb.webserver.common.pojo.base.BaseResponse;
import com.upb.webserver.common.properties.WebServerProperties;
import com.upb.webserver.common.returncode.ConstantCode;
import com.upb.webserver.common.tools.JsonUtils;
import com.upb.webserver.dao.entity.TbChain;
import com.upb.webserver.dao.mapper.*;
import com.upb.webserver.message.MessageService;
import com.upb.webserver.org.OrgService;
import com.upb.webserver.rest.fisco.FiscoChainMgrRestService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;

import static com.upb.webserver.common.constant.MessageConstant.DELETE_CHAIN_FORMAT;

@Slf4j
@Service
public class DeleteChainService {
    @Autowired
    private ChainManager chainManager;
    @Autowired
    private OrgService orgService;
    @Autowired
    private ChainOrgManager chainOrgManager;
    @Autowired
    private MessageService messageService;
    @Autowired
    private TbChainMapper chainMapper;
    @Autowired
    private WebServerProperties webServerProperties;
    @Autowired
    private TbChainOrgMapper chainOrgMapper;
    @Autowired
    private TbApplicationMapper applicationMapper;
    @Autowired
    private TbContractMapper contractMapper;
    @Autowired
    private TbApplicationOrgMapper applicationOrgMapper;
    @Autowired
    private TbDeveloperAppMapMapper developerAppMapMapper;
    @Autowired
    private TbWorkOrderMapper orderMapper;
    @Autowired
    private TbChainHostMapper chainHostMapper;
    @Autowired
    private FiscoChainMgrRestService fiscoChainMgrRestService;
    @Autowired
    private TbUserMapper userMapper;


    /**
     * @param account
     * @param chainId
     */
    @Transactional
    public void deleteByChainId(String account, int chainId) {
        log.info("start exec method [deleteByChainId]. accountName:{} chainId:{}", chainId);

        //check
        TbChain tbChain = chainManager.verifyChainId(chainId);

        //get developerIdList
        List<Integer> developerIdList = listDeveloperByChainId(chainId);

        if (ChainOrAppStatusEnum.RUNNING.getId() == tbChain.getCreateStatus()) {
            log.warn("chain status is running ,not support remove, chainId:{}", chainId);
            throw new WebServerException(ConstantCode.NOT_SUPPORT_OPERATE);
        }

        //delete work order
//        TbApplicationExample appExample = MybatisExampleTools.initSampleExample(TbApplicationExample.class, new TbApplication(chainId, null));
//        List<TbApplication> appList = applicationMapper.selectByExample(appExample);
//        List<Integer> appIdList = new ArrayList<>();
//        if (!CollectionUtils.isEmpty(appIdList)) {
//            appIdList = appList.stream().map(a -> a.getId()).collect(Collectors.toList());
//            orderMapper.deleteByTargetTableAndTargetIdList(TableNameEnum.APPLICATION.getName(), appIdList);
//        }
        //delete all application by chainId
        orderMapper.deleteAllApplicationByChainId(chainId);
        //delete workOrder about
        orderMapper.deleteByTargetTableAndTargetIdList(TableNameEnum.CHAIN.getName(), Arrays.asList(chainId));
        //delete chain org
        chainOrgMapper.deleteByChainId(chainId);
        //delete app org
        applicationOrgMapper.deleteByChainId(chainId);
        //delete  application
        applicationMapper.deleteByChainId(chainId);
        //delete chain
        chainMapper.deleteByPrimaryKey(chainId);
        //delete chain-host
        chainHostMapper.deleteByChainId(chainId);
        // delete contract
        contractMapper.deleteByChainId(chainId);
        // delete user
        userMapper.deleteByChainId(chainId);
        //delete worOrder of cross chain
        //TODO

        //delete developer app map
        developerAppMapMapper.deleteByChainId(chainId);

        if (ChainTypeEnum.FISCO.getId() == tbChain.getChainType()) {
            //delete from chain-manager
            BaseResponse baseResponse = fiscoChainMgrRestService.deleteIfRemoteChainExist(chainId);
            log.info("delete chain from fiscoChainMgr.  baseResponse:{}", JsonUtils.objToString(baseResponse));
            if (Constant.HTTP_SUCCESS_RESPONSE_CODE != baseResponse.getCode()) {
                log.warn("fail exec method[deleteByChainId], fail delete chain from fiscoChainMgr by chainId:{}", chainId);
                throw new WebServerException(baseResponse.getCode(), baseResponse.getMessage());
            }

        } else {
            log.warn("fail exec method [deleteByChainId] ,not support chainType:{}", tbChain.getChainType());
            throw new WebServerException(ConstantCode.CHAIN_TYPE_NOT_SUPPORT);
        }


        //send message
        sendMessageAfterDeveloperDeleteChain(account, developerIdList, tbChain);
        log.info("success exec method [deleteByChainId]. chainId:{}", chainId);
    }


    /**
     * @param developerName
     * @param developerIdList
     * @param chain
     */
    public void sendMessageAfterDeveloperDeleteChain(String developerName, List<Integer> developerIdList, TbChain chain) {
        log.info("start exec method [sendMessageAfterDeveloperDeleteChain].  developerName:{} chainId:{} ", developerName, chain.getId());
        try {
            String message = String.format(DELETE_CHAIN_FORMAT, developerName, chain.getId(), chain.getName());
            //send
            messageService.addInfoMessage(PlatformEnum.DEVELOPER.getId(), developerIdList, message);
            log.info("success exec method [sendMessageAfterDeveloperDeleteChain].");
        } catch (Exception ex) {
            log.warn("fail exec method [sendMessageAfterDeveloperDeleteChain].", ex);
        }
    }


    /**
     * @param chainId
     * @return
     */
    public List<Integer> listDeveloperByChainId(int chainId) {
        log.info("start exec method [listDeveloperByChainId].  chainId:{} ", chainId);
        List<Integer> orgIdList = chainOrgManager.listOrgIdByChainId(chainId);
        List<Integer> developerIdList = orgService.listDeveloperIdByOrgIdList(orgIdList);
        log.info("success exec method [listDeveloperByChainId].  chainId:{} result:{}", chainId, JsonUtils.objToString(developerIdList));
        return developerIdList;
    }
}
